<?php

// @formatter:off
/**
 * @file WCDirectory.php
 * @author Alejandro Dario Simi
 * @date $Date: 2014-06-03 03:40:32 +0000 (Tue, 03 Jun 2014) $
 *
 * $Id: WCDirectory.php 112 2014-06-03 03:40:32Z daemonraco@gmail.com $
 * $URL: http://wcomix.googlecode.com/svn/trunk/includes/representations/WCDirectory.php $
 */
// @formatter:on

/**
 * @class WCDirectory This class represents entries saved in the table
 * '%directories'.
 */
class WCDirectory extends WCRepresentationGroup implements WCPreviews, WCSearchIndexable, WCCountComics, WCCountDirectories, WCCountImages, WCFlowContainer {
	/**
	 * @var string[] This variable holds the list of columns that cannot be
	 * directly modified by the pseudo-method __set().
	 * In this case dir_id, dir_group and dir_name.
	 */
	protected $_PropertiesReadOnly = array(
		"id",
		"group",
		"name"
	);
	/**
	 * @var string[] This variable holds the list of columns that must be
	 * treated as booleans and then send to the database as 'Y' and 'N' by
	 * the pseudo-method __set().
	 * In this case col_valid_preview and col_indexed.
	 */
	protected $_PropertiesBoolean = array(
		"indexed",
		"lost",
		"valid_flow",
		"valid_preview"
	);
	/**
	 * @var string This is the prefix of every column on the table
	 * '%directories'.
	 */
	protected $_PropertiesPrefix = "dir_";
	/**
	 * @var string This is the name of the represented table. In this case,
	 * '%directories'.
	 */
	protected $_PropertiesTable = "directories";
	/**
	 * @var string This variable holds the full path to group's root
	 * directory. It's the same than method 'WCGroup::root()'.
	 */
	protected $_root = false;
	/**
	 * @var WCGContainer This container holds all comics that are physically
	 * present in this directory.
	 */
	protected $_comics = false;
	/**
	 * @var WCGContainer This container holds all images that are physically
	 * present in this directory.
	 */
	protected $_images = false;
	/**
	 * @var WCGContainer This container holds all subdirectories that, based
	 * on their paths, are supposed to be physically in this directory.
	 */
	protected $_directories = false;
	protected $_previews = array();
	protected $_previewsLoaded = false;
	//
	// Magic methods.
	/**
	 * Class basic destructor.
	 */
	public function __destruct() {
		//
		// This class has nothing to clean before deleting.
	}
	//
	// Public methods.
	/**
	 * This method allows to get a directory base-name.
	 *
	 * @return string Returns a directory name.
	 */
	public function basename() {
		return basename($this->name);
	}
	/**
	 * This method allows to get the list of comic ids that belongs to this
	 * directory.
	 *
	 * @return int[] Returns a list of comics.
	 */
	public function comics() {
		//
		// Loading members list
		$this->loadMembers();
		//
		// If there are no issues it returns the list, otherwise, it
		// returns false.
		return $this->ok() ? $this->_comics->ids() : false;
	}
	/**
	 * This method allows to get the list of comics that belongs to this
	 * directory.
	 *
	 * @return WCComics[] Returns a list of comics.
	 */
	public function comicsFull() {
		//
		// Loading members list
		$this->loadMembers();
		//
		// If there are no issues on this object, the list of items of its
		// container is returned, otherwise, an empty array is returned.
		return $this->ok() ? $this->_comics->items() : array();
	}
	/**
	 * This method allows to know how many comics belong to this directory.
	 *
	 * @return int Returns the number of members.
	 */
	public function countComics() {
		return $this->count;
	}
	/**
	 * This method allows to know how many subdirectories belong to this
	 * directory.
	 *
	 * @return int Returns the number of members.
	 */
	public function countDirectories() {
		return $this->dcount;
	}
	/**
	 * This method allows to know how many images belong to this directory.
	 *
	 * @return int Returns the number of members.
	 */
	public function countImages() {
		return $this->icount;
	}
	public function countItems() {
		return $this->countComics() + $this->countImages() + $this->countDirectories();
	}
	/**
	 * This method returns the full path of the directory.
	 *
	 * @return string Returns a system full path.
	 */
	public function fullPath() {
		return $this->path();
	}
	public function flow() {
		return WCFlowManager::I()->flowOf($this);
	}
	public function flowType() {
		return WCFlowManager::TypeDirectoryFlow;
	}
	public function generateFlow() {
		$items = array();

		foreach($this->comicsFull() as $item) {
			$items[] = $item;
		}
		foreach($this->imagesFull() as $item) {
			$items[] = $item;
		}

		$this->setValidFlow(WCFlowManager::I()->registerFlow($this, $items));
	}
	/**
	 * @todo doc
	 *
	 * @return boolean Returns true if a previews list was generated.
	 */
	public function generatePreviews() {
		//
		// This is the value to return by default.
		$out = false;
		//
		// Invalidating view cache.
		WCViewManager::I()->invalidate(WCViewManager::KeyDirectory, $this->id());

		if(WCPreviewsManager::I()->createDirectoryPreviews($this)) {
			//
			// Directory's previews are set as valid.
			$this->setValidPreviews(true);
			//
			// At this point, it is considered that a list of
			// previews was found and set to the current
			// directory.
			$out = true;

			$this->_previewsLoaded = false;
		}
		//
		// This is a good opportunity to update item's counts.
		$this->updateStats();
		//
		// Returning generation results.
		return $out;
	}
	/**
	 * This method allows to know if this directory has comics.
	 *
	 * @return boolean Returns true when it has at least one comic.
	 */
	public function hasComics() {
		return $this->count > 0;
	}
	/**
	 * This method allows to know if this directory has images.
	 *
	 * @return boolean Returns true when it has at least one image.
	 */
	public function hasDirectories() {
		return $this->dcount > 0;
	}
	/**
	 * This method allows to know if this directory has subdirectories.
	 *
	 * @return boolean Returns true when it has at least one subdirectory.
	 */
	public function hasImages() {
		return $this->icount > 0;
	}
	public function hasItems() {
		return $this->hasComics() || $this->hasImages() || $this->hasDirectories();
	}
	/**
	 * This method checks if there is a preview for this directory.
	 *
	 * @return boolean Returns true when there's a preview for this
	 * directory.
	 */
	public function hasPreview() {
		//
		// It has the same result as hasPreviews().
		return $this->hasPreviews();
	}
	/**
	 * This method checks if there are previews for this directory.
	 *
	 * @return boolean Returns true when there are previews for this
	 * directory.
	 */
	public function hasPreviews() {
		$this->loadPreviews();

		return count($this->_previews) > 0;
	}
	public function hasValidFlow() {
		return $this->valid_flow;
	}
	public function hasValidPreviews() {
		return $this->valid_preview;
	}
	/**
	 * This method allows to know whether an item is indexed or not. Also it
	 * allows to change such status.
	 *
	 * @param boolean $value New status to be set. When absent, this method
	 * works as a getter.
	 * @return boolean Returns true when the object is indexed.
	 */
	public function indexed($value = null) {
		if(!is_null($value)) {
			$this->indexed = $value;
		}

		return $this->indexed;
	}
	/**
	 * This method allows to know it the physical directory had modifications
	 * since the last check.
	 *
	 * @return boolean Returns true when a modification is detected.
	 */
	public function isChanged() {
		//
		// Setting the default value to be returned.
		$out = false;
		//
		// Checking if this directory has no issues.
		if($this->ok()) {
			//
			// Getting system information of the physical directory.
			$st = $this->stat();
			//
			// If any time property of the directory differ with
			// that saved in the database, it is considered as
			// modified.
			$out = $st["mtime"] != $this->mtime || $st["ctime"] != $this->ctime || $st["atime"] != $this->atime;
		}
		//
		// If a modification was detected and it's previews are
		// considered to be valid, this must change.
		if($out && $this->hasValidPreviews()) {
			$this->setValidPreviews(false);
		}
		//
		// Returning check's results.
		return $out;
	}
	/**
	 * This method allows to get the list of image ids that belongs to this
	 * directory.
	 *
	 * @return int[] Returns a list of images.
	 */
	public function images() {
		//
		// Loading members list
		$this->loadMembers();
		//
		// If there are no issues it returns the list, otherwise, it
		// returns false.
		return $this->ok() ? $this->_images->ids() : false;
	}
	/**
	 * This method allows to get the list of images that belongs to this
	 * directory.
	 *
	 * @return WCImages[] Returns a list of images.
	 */
	public function imagesFull() {
		//
		// Loading members list
		$this->loadMembers();
		//
		// If there are no issues on this object, the list of items of its
		// container is returned, otherwise, an empty array is returned.
		return $this->ok() ? $this->_images->items() : array();
	}
	/**
	 * This method is a re-implementation of its parent method to add some
	 * specific checks.
	 *
	 * @param int $id Directory id to load.
	 * @param WCGroup $group Group to which the directory is associated.
	 * @return boolean Returns true when it loads without issues.
	 */
	public function load($id) {
		//
		// Calling for the inherited method.
		parent::load($id);
		//
		// If it's ok, it means the parent loaded had no issues.
		if($this->ok()) {
			//
			// Setting root directory based on its group.
			$this->_root = $this->group()->root();
			//
			// Checking if the physical directory exists and if it
			// is readable.
			// @{
			$fullPath = $this->fullPath();
			if(!is_dir($fullPath) || !is_readable($fullPath)) {
				//
				// If it's not a directory, it is considered as
				// lost.
				if(!is_dir($fullPath)) {
					$this->lost = true;
				}
				//
				// At this point, the directory is no good.
				$this->_ok = false;
			}
			// @}
			//
			// Cleaning containers.
			// @{
			if($this->_comics !== null) {
				$this->_comics = null;
			}
			if($this->_images !== null) {
				$this->_images = null;
			}
			if($this->_directories !== null) {
				$this->_directories = null;
			}
			// @}
			//
			// Ensuring containers existence.
			$this->createContainers();
		}
		//
		// Returning loading results.
		return $this->ok();
	}
	/**
	 * This method attempts to load the object based on a directory path. The
	 * path to search must be a full path from the root directory of the
	 * specified group.
	 *
	 * @param string $directory Full path to look for.
	 * @param WCGroup $group Group where the directory to look for belongs.
	 * @return boolean Returns true when it was successfully loaded.
	 */
	public function loadByPath(string $directory, WCGroup &$group) {
		//
		// Setting internal properties to their initial states.
		// @{}
		$this->_info = array();
		$this->_ok = false;
		// @}
		//
		// Preparing a statement to search in the database a directory
		// based on the requested path.
		// @{}
		$stmt = null;
		$stmtID = __CLASS__."::".__FUNCTION__;
		if($this->_db->has($stmtID)) {
			$stmt = $this->_db->get($stmtID);
		} else {
			$query = "select  *\n";
			$query .= "from    {$this->_dbprefix}directories\n";
			$query .= "where   dir_group = :group\n";
			$query .= " and    dir_name  = :name\n";

			$stmt = $this->_db->prepare($stmtID, $query);
		}
		// @}
		//
		// Asking for the path.
		// @{
		$params = array(
			":group" => $group->id,
			":name" => $directory
		);
		if($stmt->execute($params) && $stmt->rowCount() > 0) {
			//
			// At this point, a match was found and it should be
			// loaded using main loader method.
			$result = $stmt->fetch();
			$this->load($result["dir_id"], $group);
		}
		// @}
		//
		// Returning load status.
		return $this->ok();
	}
	/**
	 * This method allows to get the list of comic ids that belongs to this
	 * directory.
	 *
	 * @return int[] Returns a list of comics.
	 */
	public function members() {
		/** @deprecated */
		return $this->comics();
	}
	/**
	 * This method allows to get the list of comics that belongs to this
	 * directory.
	 *
	 * @return WCComics[] Returns a list of comics.
	 */
	public function membersFull() {
		/** @deprecated */
		return $this->comicsFull();
	}
	/**
	 * This method allows to get this directory's name. It is different to
	 * directly use the property 'name' through pseudo-method __get()
	 * because, in this case, if directory is scheduled to be rename, it
	 * returns the name it will have.
	 * This provides a transparent use of the directory name beyond any
	 * renaming.
	 *
	 * @return string Returns the name of the represented directory.
	 */
	public function name() {
		//
		// Choosing and returning the right name.
		return $this->next_name ? $this->next_name : $this->name;
	}
	/**
	 * This method allows to get the parent directory for the current one.
	 *
	 * @return WCDirectory Parent directory.
	 */
	public function parentDirectory() {
		//
		// Setting the default value to returned.
		$out = false;
		//
		// Expanding directory names based on the current one.
		$parentDir = explode("/", $this->name);
		//
		// Removing the last item because it is the base-name for this
		// directory.
		array_pop($parentDir);
		//
		// If there's only one element, it is the root directory,
		// otherwise it is inploded.
		$parentDir = count($parentDir) == 1 ? "/" : implode("/", $parentDir);
		//
		// Looking for the built directory path.
		// @{
		$group = $this->group();
		$directory = WCDirectoriesHolder::I()->itemByNameInGroup($parentDir, $group);
		$directory = array_shift($directory);
		// @}
		//
		// If it's found it's assigned to be returned. Otherwise it's
		// considered to have no parent directory configured on database.
		if($directory && $directory->ok()) {
			if($directory->id != $this->id) {
				$out = $directory;
			}
		}
		//
		// Returning found directory.
		return $out;
	}
	public function path() {
		return $this->group()->root.$this->name;
	}
	/**
	 * This method allows to get the thumbnail associated with current
	 * directory.
	 *
	 * @return string Returns an image URIs.
	 */
	public function preview() {
		if($this->hasPreview()) {
			$list = $this->_previews;
			return array_shift($list);
		} else {
			global $wcDefaults;
			return $wcDefaults["preview"];
		}
	}
	/**
	 * This method allows to get the list of thumbnails associated with
	 * current directory.
	 *
	 * @return string[] Returns a list of image URIs.
	 */
	public function previews() {
		$this->loadPreviews();

		return $this->_previews;
	}
	public function reload() {
		$this->_root = false;
		$this->_comics = false;
		$this->_images = false;
		$this->_directories = false;

		return parent::reload();
	}
	/**
	 * This method allows to get the full path to this directory's group
	 * root. It's similar to method 'WCGroup::root()'.
	 *
	 * @return string Returns the full path of group's root directory.
	 */
	public function root() {
		return $this->_root;
	}
	/**
	 * This method performs the scheduled renaming operation.
	 *
	 * @return boolean Returns true when the operation was performed without
	 * issues. If the comic was not scheduled for renaming, it returns false.
	 */
	public function setNextName() {
		//
		// Loading global pointers.
		global $wcDefaults;
		//
		// Setting default value to be returned.
		$ok = false;
		//
		// Checking that Read Only Mode is not activated.
		if(!$wcDefaults["read-only"]) {
			//
			// This is the default value to be returned.
			$ok = true;
			//
			// Generating full paths for origin and destination.
			$oldPath = WCSanitizer::SystemPath("{$this->root()}{$this->name}");
			$newPath = WCSanitizer::SystemPath("{$this->root()}{$this->next_name}");
			//
			// Making some preliminary checks:
			//	- If the directory wasn't scheduled, it is an
			//	  error.
			//	- If the current full path isn't a directory, it
			//	  is an error.
			//	- If the destination full path is an existing
			//	  file, it is an error.
			$ok = $this->next_name != "" && is_dir($oldPath) && !file_exists($newPath);
			//
			// If everything is ok, the file is renamed.
			if($ok) {
				//
				// Renaming the directory.
				rename($oldPath, $newPath);
				//
				// Checking that the new directory exists and the
				// old one doesn't.
				$ok = !is_dir($oldPath) && is_dir($newPath);
			}
			//
			// If the directory was successfully renamed database must
			// reflect this.
			if($ok) {
				//
				// Preparing a statement to update the directory.
				// @{
				$stmt = false;
				$stmtID = __CLASS__."::".__FUNCTION__."[directories]";
				if($this->_db->has($stmtID)) {
					$stmt = $this->_db->get($stmtID);
				} else {
					$query = "update  {$this->_dbprefix}directories\n";
					// Current name should be the new one.
					$query .= "set     dir_name      = :name_s,\n";
					// Directory is no longer scheduled for
					// renaming.
					$query .= "        dir_next_name = '',\n";
					// It's name changed, so, it must be
					// re-indexed by the search engine.
					$query .= "        dir_indexed   = 'N'\n";
					$query .= "where   dir_group = :group\n";
					$query .= " and    dir_id    = :id\n";

					$stmt = $this->_db->prepare($stmtID, $query);
				}
				// @}
				//
				// Sending updates to the database.
				$stmt->execute(array(
					":name_s" => $this->next_name,
					":group" => $this->group()->id(),
					":id" => $this->id
				));
				//
				// Many properties of the directory had changed,
				// therefore, to avoid problems, it is reloaded.
				$ok = $this->load($this->id, $this->group());
			}
		}
		//
		// Returning the process results.
		return $ok;
	}
	public function setValidFlow($valid = true) {
		$this->valid_flow = $valid;
	}
	public function setValidPreviews($valid = true) {
		$this->valid_preview = $valid;
	}
	/**
	 * This method ask for the physical directory descriptor information.
	 *
	 * @return string[string] Returns the same value than function 'stat()'.
	 */
	public function stat() {
		return $this->ok() ? stat("{$this->root()}{$this->name}") : false;
	}
	/**
	 * This method looks for other directories that, based on their paths,
	 * are sub-directories of the current one.
	 *
	 * @return WCDirectory[] Returns a list of directories.
	 */
	public function subDirectories() {
		//
		// Checking that the list of sub-directories is not yet loaded.
		if($this->ok() && !$this->_directories->count()) {
			//
			// Clearing any previews load information.
			$this->_directories->reset();
			//
			// Preparing a statement to load the list of possible
			// sub-directories.
			// @{
			$stmt = null;
			$stmtId = __CLASS__."::".__FUNCTION__;
			if($this->_db->has($stmtId)) {
				$stmt = $this->_db->get($stmtId);
			} else {
				$query = "select  dir_id,\n";
				$query .= "        dir_name\n";
				$query .= "from    {$this->_dbprefix}directories\n";
				$query .= "where   dir_group = :group\n";
				$query .= " and    dir_name  like concat(:name,'/%')\n";
				$query .= "order by dir_name asc\n";

				$stmt = $this->_db->prepare($stmtId, $query);
			}
			// @}
			//
			// Asking for the list of sub-directories.
			// @{
			$params = array(
				":group" => $this->group()->id,
				":name" => $this->name == "/" ? "" : $this->name
			);
			if($stmt->execute($params)) {
				//
				// Counting how many directory names are in this
				// directory's path.
				$jumps = count(explode("/", $this->name)) + ($this->name != "/" ? 1 : 0);
				//
				// Analyzing each database result.
				foreach($stmt->fetchAll() as $row) {
					//
					// If a found directory is equal to the
					// current one, it's not a sub-directory.
					if($row["dir_id"] == $this->id) {
						continue;
					}
					//
					// If the amount of names in a found path
					// is more than one name longer, it's
					// inside sub-directory and it's ignored.
					if(count(explode("/", $row["dir_name"])) != $jumps) {
						continue;
					}
					//
					// At this point, it is considered to be
					// a sub-directory, therefore, it's added
					// to the list.
					$this->_directories->addId($row["dir_id"]);
				}
			}
			// @}
		}
		//
		// Returning the list of sub-directories.
		return $this->_directories->items();
	}
	/**
	 * This method sets in the database entry of this directory the current
	 * values of the physical directory times (gotten with 'stat()').
	 */
	public function updateTimes() {
		//
		// Loading global pointers.
		global $wcDefaults;
		//
		// Setting the default value to be returned.
		$out = false;
		//
		// This operation can only be run if there's no problem with
		// this object and Read Only Mode is not activated.
		if(!$wcDefaults["read-only"] && $this->ok()) {
			//
			// Invalidating view cache.
			WCViewManager::I()->invalidate(WCViewManager::KeyDirectory, $this->id());
			//
			// Getting current data from the physical descriptor.
			$st = $this->stat();
			//
			// Creating a statement to update the database entry.
			// @{
			$stmt = null;
			$stmtId = __CLASS__."::".__FUNCTION__;
			if($this->_db->has($stmtId)) {
				$stmt = $this->_db->get($stmtId);
			} else {
				$query = "update  {$this->_dbprefix}directories\n";
				$query .= "set     dir_atime = :atime,\n";
				$query .= "        dir_mtime = :mtime,\n";
				$query .= "        dir_ctime = :ctime\n";
				$query .= "where   dir_group = :group\n";
				$query .= " and    dir_id    = :id\n";
				$stmt = $this->_db->prepare($stmtId, $query);
			}
			// @}
			//
			// Setting the updated data.
			// @{
			$params = array(
				":atime" => $st["atime"],
				":mtime" => $st["mtime"],
				":ctime" => $st["ctime"],
				":group" => $this->group()->id,
				":id" => $this->id
			);
			if($out = $stmt->execute($params)) {
				//
				// Reloading the object with the updated data.
				$out = $this->load($this->id);
				//
				// Forcing an update of previews.
				$this->generatePreviews();
			}
			// @}
		}
		//
		// Returning operation status.
		return $out;
	}
	/**
	 * This method allows to get a list of phrases that must be associated
	 * with an item.
	 *
	 * @return string[] Returns a list of phrases.
	 */
	public function words() {
		return WCSearch::StringToPatterns($this->name());
	}
	//
	// Protected methods
	/**
	 * The method creates all required containers.
	 */
	protected function createContainers() {
		//
		// Checking comics container.
		if(!$this->_comics) {
			//
			// Creating a list for comics.
			$this->_comics = new WCContainer(WCComicsHolder::I());
		}
		//
		// Checking comics container.
		if(!$this->_images) {
			//
			// Creating a list for comics.
			$this->_images = new WCContainer(WCImagesHolder::I());
		}
		//
		// Checking sub-directories container.
		if(!$this->_directories) {
			//
			// Creating a list for sub-directories.
			$this->_directories = new WCContainer(WCDirectoriesHolder::I());
		}
	}
	/**
	 * This method loads the list of comics and images belonging to this directory.
	 * @note Sub-directories' comics are not considered as members.
	 */
	protected function loadMembers() {
		//
		// Ensuring containers existence.
		$this->createContainers();
		//
		// Checking that this directory is ok and the comics list is
		// not loaded yet.
		if($this->ok() && !$this->_comics->count()) {
			//
			// Clearing any previews load information.
			$this->_comics->reset();
			//
			// Creating a statement to load comics.
			// @{
			$stmt = null;
			$stmtId = __CLASS__."::".__FUNCTION__."[comics]";
			if($this->_db->has($stmtId)) {
				$stmt = $this->_db->get($stmtId);
			} else {
				$query = "select  *\n";
				$query .= "from    {$this->_dbprefix}comics\n";
				$query .= "where   cmc_group     = :group\n";
				$query .= " and    cmc_directory = :directory\n";
				$query .= " and    cmc_lost      = 'N'\n";
				$query .= "order by cmc_name asc\n";

				$stmt = $this->_db->prepare($stmtId, $query);
			}
			// @}
			//
			// Asking for comics.
			// @{
			$params = array(
				":group" => $this->group()->id,
				":directory" => $this->id
			);
			if($stmt->execute($params)) {
				//
				// Adding found comics to the list.
				foreach($stmt->fetchAll() as $row) {
					$this->_comics->addId($row["cmc_id"], $row);
				}
			}
			// @}
		}
		//
		// Checking that this directory is ok and the images list is
		// not loaded yet.
		if($this->ok() && !$this->_images->count()) {
			//
			// Clearing any previews load information.
			$this->_images->reset();
			//
			// Creating a statement to load comics.
			// @{
			$stmt = null;
			$stmtId = __CLASS__."::".__FUNCTION__."[images]";
			if($this->_db->has($stmtId)) {
				$stmt = $this->_db->get($stmtId);
			} else {
				$query = "select  *\n";
				$query .= "from    {$this->_dbprefix}images\n";
				$query .= "where   img_group     = :group\n";
				$query .= " and    img_directory = :directory\n";
				$query .= " and    img_lost      = 'N'\n";
				$query .= "order by img_name asc\n";

				$stmt = $this->_db->prepare($stmtId, $query);
			}
			// @}
			//
			// Asking for images.
			// @{
			$params = array(
				":group" => $this->group()->id,
				":directory" => $this->id
			);
			if($stmt->execute($params)) {
				//
				// Adding found comics to the list.
				foreach($stmt->fetchAll() as $row) {
					$this->_images->addId($row["img_id"], $row);
				}
			}
			// @}
		}
	}
	protected function loadPreviews() {
		if(!$this->_previewsLoaded) {
			$this->_previews = WCPreviewsManager::I()->getPreviews($this->group(), WCPreviewsManager::TypeDirectory, $this->id());

			if(count($this->_previews) <= 0) {
				$this->setValidPreviews(false);
			} else {
				global $wcPaths;
				foreach($this->_previews as $key => $value) {
					$this->_previews[$key] = WCSanitizer::WComixPath("{$wcPaths["cache-directory-uri"]}/{$wcPaths["cache-thumbs-dirname"]}/{$value}");
				}
			}

			$this->_previewsLoaded = true;
		}
	}
	/**
	 * This is an internal method called by the pseudo-method __set().
	 *
	 * @param string $name Name of the parameter being modified.
	 * @param string $value Value to set to the property with name $name.
	 * @param string $realValue Value built by the pseudo-method __set().
	 * @return boolean Returns true when it is alright to modify the property.
	 */
	protected function subSet($name, &$value, &$realValue) {
		//
		// Invalidating view cache.
		WCViewManager::I()->invalidate(WCViewManager::KeyDirectory, $this->id());
		//
		// If name is scheduled to be change it must be re-indexed by the
		// search engine.
		if($name == "next_name") {
			$this->indexed = false;
			//
			// If the new name is that same than the old one, the
			// scheduled operation for renaming must be removed.
			if($value == $this->name) {
				$value = "";
			}
		}
		//
		// There are no conditions in this method that my interrupt the
		// property change.
		return true;
	}
	protected function updateStats() {
		//
		// Creating a statement request members of this directory.
		// @{
		$stmt = null;
		$stmtId = __CLASS__."::".__FUNCTION__."[stats]";
		if($this->_db->has($stmtId)) {
			$stmt = $this->_db->get($stmtId);
		} else {
			$query = "update  {$this->_dbprefix}directories\n";
			$query .= "set     dir_count = (\n";
			$query .= "                select  count(*)\n";
			$query .= "                from    {$this->_dbprefix}comics\n";
			$query .= "                where   cmc_directory = :directory\n";
			$query .= "                 and    cmc_lost      = 'N'\n";
			$query .= "        ),\n";
			$query .= "        dir_icount = (\n";
			$query .= "                select  count(*)\n";
			$query .= "                from    {$this->_dbprefix}images\n";
			$query .= "                where   img_directory = :directory\n";
			$query .= "                 and    img_lost      = 'N'\n";
			$query .= "        )\n";
			$query .= "where   dir_id = :directory\n";

			$stmt = $this->_db->prepare($stmtId, $query);
		}
		// @}
		//
		// Building database parameters.
		$params = array(":directory" => $this->id);
		$stmt->execute($params);
		$stmt->closeCursor();
		//
		// Directory flow may no longer be valid.
		$this->setValidFlow(false);
	}
	//
	// Public class methods.
	/**
	 * This is a sorting method based on directory ids and it can be used on
	 * usort and uasort functions.
	 *
	 * @param WCDirectory $a Left operand.
	 * @param WCDirectory $b Right operand.
	 * @return boolean Returns true when the id of $a is greater than $b's.
	 */
	public static function IdSort(WCDirectory &$a, WCDirectory &$b) {
		return $a->id > $b->id;
	}
	/**
	 * This is a sorting method based on directory names and it can be used on
	 * usort and uasort functions.
	 *
	 * @param WCDirectory $a Left operand.
	 * @param WCDirectory $b Right operand.
	 * @return boolean Returns true when the name of $a is greater than
	 * $b's.
	 */
	public static function NameSort(WCDirectory &$a, WCDirectory &$b) {
		return strtolower($a->name) > strtolower($b->name);
	}
	/**
	 * This is the general sorting method and it can be used on usort and
	 * uasort functions.
	 *
	 * @param WCDirectory $a Left operand.
	 * @param WCDirectory $b Right operand.
	 * @return boolean Returns true when $a goes after $b.
	 */
	public static function Sort(WCDirectory &$a, WCDirectory &$b) {
		return self::NameSort($a, $b);
	}
}
